import { Router } from 'express';

import Paths from '@src/common/constants/Paths';
import { prisma } from '@src/common/database';
import { jsonResponse } from '@src/common/util/bigint-serializer';

import crypto from 'crypto';
const router = Router();
import { attachLiveSSE, sendToLiveRoom } from './common/live-sse';
import { getLiveTrialState, setLiveTrialState } from '@src/common/live-trial';

// 工具：获取当前登录用户
async function getCurrentUser(req: any) {
  try {
    const sid = req.cookies?.['sid'];
    if (!sid) return null;
    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
    if (!sess || new Date(sess.expiredAt) < new Date()) return null;
    const user = await prisma.user.findUnique({ where: { id: sess.userId } });
    return user;
  } catch {
    return null;
  }
}


// GET /api/live/rooms - 获取活跃直播间列表
router.get(Paths.Live.Rooms, async (req, res) => {
  try {
    const { page = 1, limit = 20, search } = req.query;
    const offset = (Number(page) - 1) * Number(limit);

    // 构建搜索条件
    const whereCondition: any = {
      status: 'active',
    };

    // 如果有搜索关键词，添加搜索条件
    if (search && typeof search === 'string' && search.trim()) {
      const searchTerm = search.trim();
      whereCondition.OR = [
        {
          title: {
            contains: searchTerm,
            mode: 'insensitive',
          },
        },
        {
          channel: {
            name: {
              contains: searchTerm,
              mode: 'insensitive',
            },
          },
        },
      ];
    }

    const liveRooms = await prisma.liveRoom.findMany({
      where: whereCondition,
      skip: offset,
      take: Number(limit),
      orderBy: { startedAt: 'desc' },
      select: {
        id: true,
        channelId: true,
        title: true,
        status: true,
        coverUrl: true,
        startedAt: true,
        endedAt: true,
        replayVideoId: true,
        manualViewerCount: true,
        channel: {
          select: {
            id: true,
            name: true,
            avatarUrl: true,
          },
        },
        replayVideo: {
          select: {
            id: true,
            title: true,
            fileUrl: true,
            coverUrl: true,
            durationSec: true,
          },
        },
        presets: {
          where: { isActive: true },
          orderBy: { sortOrder: 'asc' },
          select: {
            id: true,
            content: true,
            sortOrder: true,
          },
        },
      },
    });

    const total = await prisma.liveRoom.count({
      where: whereCondition,
    });

    return jsonResponse(res, {
      liveRooms,
      total,
      page: Number(page),
      limit: Number(limit),
    });
  } catch (err) {
    console.error('라이브 방 목록 조회 실패:', err);
    return res.status(500).json({ error: '라이브 방 목록 조회 실패' });
  }
});

// GET /api/live/rooms/:id - 获取直播间详情
router.get(Paths.Live.Rooms + '/:id', async (req, res) => {
  try {
    const { id } = req.params;

    const liveRoom = await prisma.liveRoom.findUnique({
      where: { id: BigInt(id) },
      include: {
        channel: {
          select: {
            id: true,
            name: true,
            avatarUrl: true,
            description: true,
          },
        },
        replayVideo: {
          select: {
            id: true,
            title: true,
            description: true,
            fileUrl: true,
            coverUrl: true,
            durationSec: true,
            sizeBytes: true,
          },
        },
        presets: {
          where: { isActive: true },
          orderBy: { sortOrder: 'asc' },
          select: {
            id: true,
            content: true,
            sortOrder: true,
          },
        },
      },
    });

    if (!liveRoom) {
      return res.status(404).json({ error: '라이브 방이 존재하지 않습니다' });
    }

    if (liveRoom.status !== 'active') {
      return res.status(403).json({ error: '라이브 방이 열려있지 않습니다' });
    }

    // 登录用户：仅允许一个房间观看；无积分10秒试看，有积分可看完但之后全局禁入
    try {
      const sid = (req.cookies?.sid as string) || undefined;
      if (sid) {
        const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
        if (sess && new Date(sess.expiredAt) > new Date()) {
          const userId = sess.userId;
          const wallet = await prisma.userWallet.findUnique({ where: { userId } });
          const balance = wallet?.pointsBalance || BigInt(0);
          const hasPoints = balance > BigInt(0);

          const trial = await getLiveTrialState(userId);
          if (!trial) {
            await setLiveTrialState(userId, { roomId: String(id), ended: false, totalSec: 0, createdAt: new Date().toISOString() });
          } else {
            // 如果观看已结束，无论是哪个房间都禁止进入
            if (trial.ended) {
              return res.status(403).json({ error: hasPoints ? '시청이 종료되었습니다' : '체험 시청이 종료되었습니다' });
            }
            // 如果正在观看其他房间，禁止进入新房间
            if (trial.roomId && trial.roomId !== String(id)) {
              return res.status(403).json({ error: '하나의 라이브 방만 선택하여 시청할 수 있습니다' });
            }
          }
        }
      }
    } catch {}

    return jsonResponse(res, liveRoom);
  } catch (err) {
    console.error('라이브 방 상세 정보 가져오기 실패:', err);
    return res.status(500).json({ error: '라이브 방 상세 정보 가져오기 실패' });
  }
});

// Live SSE stream for room
attachLiveSSE(router, Paths.Live.Rooms);

// POST /api/live/rooms/:id/messages - 发送用户消息到直播间
router.post(Paths.Live.Rooms + '/:id/messages', async (req, res) => {
  try {
    const { id } = req.params as any;
    const user = await getCurrentUser(req);
    if (!user) return res.status(401).json({ error: '로그인되지 않음' });

    const { content } = req.body ?? {};
    if (!content || String(content).trim() === '') {
      return res.status(400).json({ error: '메시지 내용이 비어있을 수 없습니다' });
    }

    // 验证直播间存在且活跃
    const liveRoom = await prisma.liveRoom.findUnique({
      where: { id: BigInt(id) },
      select: { id: true, status: true }
    });
    if (!liveRoom) return res.status(404).json({ error: '라이브 방이 존재하지 않습니다' });
    if (liveRoom.status !== 'active') return res.status(403).json({ error: '라이브 방이 열려있지 않습니다' });

    // 创建消息记录（存储在LiveMessage表中，但标记为用户消息）
    const msg = await prisma.liveMessage.create({
      data: {
        liveRoomId: BigInt(id),
        adminUserId: user.id, // 暂时使用adminUserId字段存储用户ID
        content: String(content),
      },
    });

    const payload = {
      id: String(msg.id),
      content: msg.content,
      username: user.nickname || user.name || '나',
      avatar: user.avatarUrl || 'https://picsum.photos/32',
      timestamp: msg.createdAt,
      senderUserId: String(user.id),
      isUserMessage: true, // 标记为用户消息
    };

    // 广播消息到直播间
    sendToLiveRoom(String(id), 'message', payload);

    return jsonResponse(res, { ok: true, id: String(msg.id) });
  } catch (err) {
    console.error('라이브 방 메시지 전송 실패:', err);
    return res.status(500).json({ error: '메시지 전송 실패' });
  }
});

// POST /api/live/rooms/:id/viewers/heartbeat - 心跳上报
router.post(Paths.Live.Rooms + '/:id/viewers/heartbeat', async (req, res) => {
  try {
    const { id } = req.params as any;
    const liveRoomId = BigInt(id);

    // 校验直播间存在且活跃
    const room = await prisma.liveRoom.findUnique({ where: { id: liveRoomId }, select: { id: true, status: true } });
    if (!room) return res.status(404).json({ error: '라이브 방이 존재하지 않습니다' });
    if (room.status !== 'active') return res.status(403).json({ error: '라이브 방이 열려있지 않습니다' });

    // 识别用户
    const sid = (req.cookies?.sid as string) || undefined;
    let userId: bigint | null = null;
    if (sid) {
      const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
      if (sess && new Date(sess.expiredAt) > new Date()) userId = sess.userId;
    }

    // 登录用户：处理观看逻辑（无积分10秒试看，有积分可看完）
    if (userId) {
      const wallet = await prisma.userWallet.findUnique({ where: { userId } });
      const balance = wallet?.pointsBalance || BigInt(0);
      const hasPoints = balance > BigInt(0);

      const trial = await getLiveTrialState(userId);
      // 未建立 trial，允许第一次心跳同时锁定房间
      if (!trial) {
        await setLiveTrialState(userId, { roomId: String(id), ended: false, totalSec: 0, createdAt: new Date().toISOString() });
      } else {
        // 房间必须一致
        if (trial.roomId && trial.roomId !== String(id)) {
          return res.status(403).json({ error: '하나의 라이브 방만 선택하여 시청할 수 있습니다' });
        }
        // 若观看已结束，禁止继续心跳
        if (trial.ended) {
          return res.status(403).json({ error: hasPoints ? '시청이 종료되었습니다' : '체험 시청이 종료되었습니다' });
        }
      }
    }

    // 计算 ipHash（匿名用户）
    const ip = (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() || req.socket.remoteAddress || '';
    const ipHash = userId ? null : crypto.createHash('sha256').update(ip).digest('hex');

    // upsert 会话（userId 优先）
    const now = new Date();
    const MAX_GAP_SEC = 120; // 保护上限，避免长时间断线后一次性累加

    let incrementSec = 0;

    if (userId) {
      const key = { liveRoomId, userId } as const;
      const existing = await prisma.liveViewerSession.findUnique({ where: { liveRoomId_userId: key } });
      if (existing) {
        const last = new Date(existing.lastHeartbeatAt);
        const gapSec = Math.min(Math.max(0, Math.floor((now.getTime() - last.getTime()) / 1000)), MAX_GAP_SEC);
        incrementSec = gapSec;
        await prisma.liveViewerSession.update({
          where: { liveRoomId_userId: key },
          data: { lastHeartbeatAt: now, endedAt: null, watchSeconds: { increment: gapSec } },
        });
      } else {
        await prisma.liveViewerSession.create({
          data: { liveRoomId, userId, startedAt: now, lastHeartbeatAt: now, watchSeconds: 0 },
        });
      }

      // 处理观看时长：无积分用户10秒后结束，有积分用户需要手动结束观看
      const wallet = await prisma.userWallet.findUnique({ where: { userId } });
      const balance = wallet?.pointsBalance || BigInt(0);
      const hasPoints = balance > BigInt(0);

      const trial = await getLiveTrialState(userId);
      if (trial && !trial.ended) {
        const total = (trial.totalSec || 0) + incrementSec;

        if (!hasPoints && total >= 10) {
          // 无积分用户：10秒后强制结束
          await setLiveTrialState(userId, { ...trial, totalSec: total, ended: true, endedAt: new Date().toISOString() });
          return res.status(403).json({ error: '체험 시청이 종료되었습니다' });
        } else {
          // 有积分用户：只累计时长，不自动结束（需要手动结束或直播结束时触发）
          await setLiveTrialState(userId, { ...trial, totalSec: total });
        }
      }
    } else {
      const key = { liveRoomId, ipHash: ipHash! } as const;
      const existing = await prisma.liveViewerSession.findUnique({ where: { liveRoomId_ipHash: key } });
      if (existing) {
        const last = new Date(existing.lastHeartbeatAt);
        const gapSec = Math.min(Math.max(0, Math.floor((now.getTime() - last.getTime()) / 1000)), MAX_GAP_SEC);
        await prisma.liveViewerSession.update({
          where: { liveRoomId_ipHash: key },
          data: { lastHeartbeatAt: now, endedAt: null, watchSeconds: { increment: gapSec } },
        });
      } else {
        await prisma.liveViewerSession.create({
          data: { liveRoomId, ipHash: ipHash!, startedAt: now, lastHeartbeatAt: now, watchSeconds: 0 },
        });
      }
    }

    return res.json({ ok: true });
  } catch (err) {
    console.error('하트비트 실패:', err);
    return res.status(500).json({ error: '하트비트 실패' });
  }
});

// GET /api/live/rooms/:id/viewers/count - 当前在线人数
router.get(Paths.Live.Rooms + '/:id/viewers/count', async (req, res) => {
  try {
    const { id } = req.params as any;
    const liveRoomId = BigInt(id);
    const windowSec = Number(req.query.windowSec || 60);
    const threshold = new Date(Date.now() - windowSec * 1000);

    const count = await prisma.liveViewerSession.count({
      where: { liveRoomId, lastHeartbeatAt: { gt: threshold } },
    });

    return res.json({ roomId: String(id), online: count, windowSec });
  } catch (err) {
    console.error('온라인 인원수 조회 실패:', err);
    return res.status(500).json({ error: '온라인 인원수 조회 실패' });
  }
});

// GET /api/live/ranking - 排名数据（优先使用管理员设置的排名）
// query: period=all|day|week|month, orderBy=views, limit=10, offset=0
router.get('/ranking', async (req, res) => {
  try {
    const { period = 'all', orderBy = 'views', limit = '10', offset = '0' } = req.query as any;
    const l = Math.min(Math.max(Number(limit) || 10, 1), 100);
    const o = Math.max(Number(offset) || 0, 0);

    // 首先尝试获取管理员设置的排名数据
    const adminRankings = await prisma.ranking.findMany({
      where: { period: period as string },
      orderBy: { rankPosition: 'asc' },
      include: {
        channel: {
          select: {
            id: true,
            name: true,
            avatarUrl: true,
            liveRoom: {
              select: {
                coverUrl: true,
                replayVideo: {
                  select: { coverUrl: true },
                },
              },
            },
          },
        },
      },
    });

    if (adminRankings.length > 0) {
      // 使用管理员设置的排名数据
      const items = adminRankings.slice(o, o + l).map(ranking => ({
        channelId: String(ranking.channelId),
        name: ranking.channel.name,
        avatarUrl: ranking.channel.avatarUrl,
        coverUrl: ranking.channel.liveRoom?.coverUrl ||
                  ranking.channel.liveRoom?.replayVideo?.coverUrl ||
                  ranking.channel.avatarUrl,
        views: ranking.viewCount,
        watchSeconds: ranking.watchSeconds,
        giftCount: ranking.giftCount,
        score: ranking.score,
        isManual: ranking.isManual,
      }));

      const totalTopViews = items.slice(0, 5).reduce((s, x) => s + x.views, 0);
      return res.json({ items, totalTopViews, period, orderBy, limit: l, offset: o, source: 'admin' });
    }

    // 如果没有管理员设置的排名，回退到原来的逻辑
    // 时间窗口
    let since: Date | undefined;
    const now = new Date();
    if (period === 'day') {
      since = new Date(now.getTime() - 24 * 3600 * 1000);
    } else if (period === 'week') {
      since = new Date(now.getTime() - 7 * 24 * 3600 * 1000);
    } else if (period === 'month') {
      since = new Date(now.getTime() - 30 * 24 * 3600 * 1000);
    }

    // 取活跃直播间并关联频道
    const rooms = await prisma.liveRoom.findMany({
      where: {},
      select: {
        id: true,
        channelId: true,
        coverUrl: true,
        channel: { select: { id: true, name: true, avatarUrl: true } },
        replayVideo: { select: { coverUrl: true } },
      },
    });
    const roomIds = rooms.map(r => r.id);
    const channelMap = new Map<string, { channelId: bigint, name: string, avatarUrl: string | null, coverUrl: string | null }>();
    rooms.forEach(r => {
      const preferredCover = r.coverUrl || r.replayVideo?.coverUrl || r.channel.avatarUrl || null;
      channelMap.set(String(r.id), { channelId: r.channel.id, name: r.channel.name, avatarUrl: r.channel.avatarUrl || null, coverUrl: preferredCover });
    });

    if (roomIds.length === 0) return res.json({ items: [], totalTopViews: 0, period });

    // 聚合 LiveViewerSession
    const whereSession: any = { liveRoomId: { in: roomIds } };
    if (since) whereSession.startedAt = { gte: since };

    const aggregates = await prisma.liveViewerSession.groupBy({
      by: ['liveRoomId'],
      where: whereSession,
      _count: { _all: true },
      _sum: { watchSeconds: true },
    });

    // 汇总到频道维度（一个频道一个房间）
    const perChannel: Record<string, { channelId: string, name: string, avatarUrl: string | null, coverUrl: string | null, views: number, watchSeconds: number } > = {};
    for (const agg of aggregates) {
      const meta = channelMap.get(String(agg.liveRoomId));
      if (!meta) continue;
      const key = String(meta.channelId);
      if (!perChannel[key]) perChannel[key] = { channelId: key, name: meta.name, avatarUrl: meta.avatarUrl, coverUrl: meta.coverUrl, views: 0, watchSeconds: 0 };
      perChannel[key].views += agg._count._all;
      perChannel[key].watchSeconds += Number(agg._sum.watchSeconds || 0);
    }

    // 排序与分页
    const itemsAll = Object.values(perChannel).sort((a, b) => {
      if (orderBy === 'views') return b.views - a.views;
      return b.watchSeconds - a.watchSeconds;
    });

    const items = itemsAll.slice(o, o + l).map(item => ({
      ...item,
      giftCount: 0, // 原始数据没有礼物数量，设为0
      score: Math.round(item.watchSeconds / 60), // 评分=累计观看时长(分钟)
      isManual: false,
    }));
    const totalTopViews = items.slice(0, 5).reduce((s, x) => s + x.views, 0);

    return res.json({ items, totalTopViews, period, orderBy, limit: l, offset: o, source: 'auto' });
  } catch (err) {
    console.error('과거 UV 순위 조회 실패:', err);
    return res.status(500).json({ error: '과거 UV 순위 조회 실패' });
  }
});

// POST /api/live/rooms/:id/end-watching - 结束观看（有积分用户看完后调用）
router.post(Paths.Live.Rooms + '/:id/end-watching', async (req, res) => {
  try {
    const { id } = req.params as any;

    // 识别用户
    const sid = (req.cookies?.sid as string) || undefined;
    let userId: bigint | null = null;
    if (sid) {
      const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
      if (sess && new Date(sess.expiredAt) > new Date()) userId = sess.userId;
    }

    if (!userId) {
      return res.status(401).json({ error: '로그인되지 않음' });
    }

    // 检查是否有积分
    const wallet = await prisma.userWallet.findUnique({ where: { userId } });
    const balance = wallet?.pointsBalance || BigInt(0);
    const hasPoints = balance > BigInt(0);

    if (!hasPoints) {
      return res.status(403).json({ error: '포인트가 없는 사용자는 수동으로 시청을 종료할 필요가 없습니다' });
    }

    // 结束观看状态
    const trial = await getLiveTrialState(userId);
    if (trial) {
      if (trial.ended) {
        return res.status(400).json({ error: '시청이 이미 종료되었습니다' });
      }
      if (trial.roomId !== String(id)) {
        return res.status(400).json({ error: '방 ID가 일치하지 않습니다' });
      }
      // 设置观看结束
      await setLiveTrialState(userId, { ...trial, ended: true, endedAt: new Date().toISOString() });
      return res.json({ success: true, message: '시청이 종료되었습니다' });
    } else {
      // 如果没有试看状态，创建一个已结束的状态
      await setLiveTrialState(userId, {
        roomId: String(id),
        ended: true,
        totalSec: 0,
        createdAt: new Date().toISOString(),
        endedAt: new Date().toISOString()
      });
      return res.json({ success: true, message: '시청이 종료되었습니다' });
    }
  } catch (err) {
    console.error('시청 종료 실패:', err);
    return res.status(500).json({ error: '시청 종료 실패' });
  }
});

export default router;
